package com.googlecode.curvedmetromaps.core.logic.costfunction;

import java.util.ArrayList;
import java.util.HashMap;

import com.googlecode.curvedmetromaps.core.geometry.BasicGeometry;
import com.googlecode.curvedmetromaps.core.model.MetroMap;

public class CostSystem {

	public MetroMap				metroMap;

	public ArrayList<BaseCost>	costFunctions;
	
	public String log = "";

	public CostSystem(MetroMap metroMap) {
		this.metroMap = metroMap;
		this.costFunctions = new ArrayList<BaseCost>();

		this.costFunctions.add(new AdjacentVertexCost(metroMap));
		this.costFunctions.add(new AngularResolutionCost(metroMap));
		this.costFunctions.add(new ContinuityCost(metroMap));
		this.costFunctions.add(new BezierCurvatureCost(metroMap));
		this.costFunctions.add(new GeographicOrientationCost(metroMap));
		this.costFunctions.add(new InflectionCost(metroMap));
		this.costFunctions.add(new VertexEdgeDistanceCost(metroMap));
		this.costFunctions.add(new VertexVertexDistanceCost(metroMap));
		this.costFunctions.add(new MetroLineSmoothnessCost(metroMap));
		
		for (int i = 0; i < costFunctions.size(); i++) {
			if (i > 0) log += "\t";
			log += costFunctions.get(i).getName();
		}
	}

	/**
	 * Evaluate and sum all cost functions.
	 *
	 * @return Sum of all costs
	 */
	public double calculateCostSum() {
		HashMap<String, Double> costs = calculateCosts();
		
		double totalCost = 0;
		for (Double v : costs.values()) {
			totalCost += v;
		}
		
		return totalCost;
	}

	/**
	 * Evaluate all cost functions and return the cost per cost function.
	 *
	 * @return Name and cost of cost functions.
	 */
	public HashMap<String, Double> calculateCosts() {
		// Translate and scale map such that width is 1.
		BasicGeometry.normalizeMap(metroMap);
		
		// Calculate costs
		HashMap<String, Double> results = new HashMap<String, Double>();
		for (int i = 0; i < costFunctions.size(); i++) {
			BaseCost costFunction = costFunctions.get(i);
			double cost = costFunction.calculateCost();
			results.put(costFunction.getName(), cost);

			// Write cost to log
			if (i > 0) log += "\t";
			log += String.valueOf(cost);
		}

		return results;
	}
}
